package com.lengyu.iottransfer.gateway.tcp.daxiang;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.extension.api.R;
import com.lengyu.iottransfer.gateway.common.ByteUtils;
import com.lengyu.iottransfer.gateway.config.MqttSendGateway;
import com.lengyu.iottransfer.gateway.dto.MqttDeviceCurrentDto;
import com.lengyu.iottransfer.gateway.influxdb.service.impl.DeviceLogInfluxService;
import com.lengyu.iottransfer.gateway.service.IDeviceTransferService;
import io.lettuce.core.StrAlgoArgs;
import io.netty.channel.ChannelHandlerContext;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.math.RoundingMode;

@Component
public class DaxiangGuanpianTransfer {
    private static Logger logger = LoggerFactory.getLogger(DaxiangGuanpianTransfer.class);

    private static String DEVICE_TYPE="DAXIANG_GUANPIAN_MONITOR_PRODUCT";
    private static String DEVICE_CODE_PREFIX = "dxgp";

    @Resource
    private MqttSendGateway mqttSendGateway;

    @Autowired
    private IDeviceTransferService deviceTransferService;

    @Autowired
    DeviceLogInfluxService deviceLogInfluxService;

    /**
     *
     * @param byteArray
     * @return  deviceCode
     */
    public String transforToMqttData(byte[] byteArray,ChannelHandlerContext ctx){
        String hexString =  ByteUtils.byteArrayToHexString(byteArray);
        logger.info("大襄预埋传感器消息解析：" + hexString);
        if(hexString.startsWith("ce ce")){
            return processReport(byteArray);
        }
        else if(hexString.startsWith("fe fe")){
            return processDeviceConfirm(byteArray);
        }
        else if(hexString.startsWith("fa fa")){
            return processReadResult(byteArray);
        }
        else if(hexString.startsWith("c0 c0")){
            //心跳
            return processHeartBeat(byteArray,ctx);
        }
        else
            return "";

    }

    /**
     *
     * @param byteArray
     * @return devicecode
     */
    private String processHeartBeat(byte[] byteArray,ChannelHandlerContext ctx) {
        logger.info("预埋传感心跳 ");
        //网关
        String gatewayNum = ByteUtils.byteArrayToHexString(byteArray,2,2,false);
        //节点
        String nodeNum = ByteUtils.byteArrayToHexString(byteArray,4,2,false);
        //传感器
        String monitorNum = ByteUtils.byteArrayToHexString(byteArray,6,2,false);
        String deviceCode = gatewayNum +nodeNum + monitorNum;

        StringBuilder commandSb = new StringBuilder();
        commandSb.append("CA CA ");
        commandSb.append(gatewayNum + " " + nodeNum + " " + monitorNum);
        commandSb.append("87 65 00 00 00 00");
        String crcResult = ByteUtils.getCRC16(ByteUtils.hexStrToByteArray(commandSb.toString()),true);
        commandSb.append(crcResult);
        byte[] commandBytes = ByteUtils.hexStrToByteArray(commandSb.toString());
        logger.info("传感器心跳信息应答:" + ByteUtils.byteArrayToHexString(commandBytes));
        ctx.writeAndFlush(commandBytes);
        return deviceCode;
    }

    private String processReadResult(byte[] byteArray) {
        try{
            logger.info("预埋传感器读命令返回消息 ");
            //网关
            String gatewayNum = ByteUtils.byteArrayToHexString(byteArray,2,2,false);
            //节点
            String nodeNum = ByteUtils.byteArrayToHexString(byteArray,4,2,false);
            //传感器
            String monitorNum = ByteUtils.byteArrayToHexString(byteArray,6,2,false);
            String deviceCode = DEVICE_CODE_PREFIX+ "_"+gatewayNum +nodeNum + monitorNum;
            String mingling = ByteUtils.byteArrayToHexString(byteArray,8,1,false);

            String address = ByteUtils.byteArrayToHexString(byteArray,9,2,false);
            //数据长度
            int dataLength = ByteUtils.byteToInt(byteArray[9]);
            logger.info("起始地址：" + address);
            JSONObject resultJson= new JSONObject();
            if(dataLength/2 > 0){
                for(int i=0;i<dataLength/2;i++){
                    int tmpData = ByteUtils.byteArrayToShort(byteArray,10 + 2*i);
                    resultJson.put("data" + i,tmpData);
                }
            }
            if(dataLength == 10 * 2){
                logger.info("预埋传感器读命令返回消息："+deviceCode + "数据长度：" + dataLength + "预埋传感当前状态：" + JSONObject.toJSONString(resultJson));
            }
            else if(dataLength == 9* 2){
//                decodeConfig1(resultJson);
                logger.info("预埋传感器读命令返回消息："+deviceCode + "数据长度：" + dataLength + "预埋传感器参数1：" + JSONObject.toJSONString(resultJson));
            }
            else if(dataLength == 4* 2){
                logger.info("预埋传感器读命令返回消息："+deviceCode + "数据长度：" + dataLength + "预埋传感器参数2：" + JSONObject.toJSONString(resultJson));
            }

            deviceLogInfluxService.addDeviceLog(deviceCode,
                    ByteUtils.byteArrayToHexString(byteArray),"commandReadResultData",System.currentTimeMillis(),0);

            return "";
        }
        catch (Exception ex){
            logger.error("error",ex);
            return "";
        }

    }

    private JSONObject decodeConfig1(JSONObject resultJson){
        logger.info("读取配置信息解析值");
        JSONObject configJson = new JSONObject();
        for(int i=0;i<10;i++){
            BigDecimal actValue = BigDecimal.ZERO;
            if(i>=2 && i<=7){
                actValue=aDToAct4096(resultJson.getShortValue("data" + i));
                configJson.put("data" + i,actValue.toString());
            }
        }
        logger.info("读取配置信息解析值:" + configJson.toJSONString());

        return configJson;
    }

    private BigDecimal aDToAct4096(short adData){
        BigDecimal actValue = new BigDecimal(String.valueOf(adData))
                .multiply(new BigDecimal("3.3"))
                .divide(new BigDecimal("4096"),3, RoundingMode.HALF_UP);
        return actValue;
    }

    private short act4096ToAd(BigDecimal actValue){
        short valueShort= actValue.
                multiply(new BigDecimal("4096")).
                divide(new BigDecimal("3.3"),2,RoundingMode.HALF_UP).shortValue();

        return valueShort;
    }

    private String processDeviceConfirm(byte[] byteArray) {
        logger.info("预埋传感器收到平台命令后回复 ");
        //网关
        String gatewayNum = ByteUtils.byteArrayToHexString(byteArray,2,2,false);
        //节点
        String nodeNum = ByteUtils.byteArrayToHexString(byteArray,4,2,false);
        //传感器
        String monitorNum = ByteUtils.byteArrayToHexString(byteArray,6,2,false);
        String deviceCode = DEVICE_CODE_PREFIX+ "_"+gatewayNum +nodeNum + monitorNum;
        logger.info("预埋传感器收到平台命令后回复 " + deviceCode);
        deviceLogInfluxService.addDeviceLog(deviceCode,
                ByteUtils.byteArrayToHexString(byteArray),"commandDeviceConfirm",System.currentTimeMillis(),0);
        return gatewayNum +nodeNum + monitorNum;
    }

    private String processReport(byte[] byteArray){
        logger.info("预埋传感器定时上报");

        //crc16 校验
        byte[] checkBytes = new byte[byteArray.length - 2];
        System.arraycopy(byteArray,0,checkBytes,0,checkBytes.length);
        String crcResult = ByteUtils.getCRC16(checkBytes,true);

        String msgCrc = ByteUtils.byteArrayToHexString(byteArray,byteArray.length - 2,2,true);


        if (!crcResult.equalsIgnoreCase(msgCrc)) {
            logger.info("CRC校验未通过。计算的CRC：" + crcResult + " 消息的CRC：" + msgCrc);
            return "";
        }

        MqttDeviceCurrentDto mqttDeviceCurrentDto = new MqttDeviceCurrentDto();
        mqttDeviceCurrentDto.setTime(System.currentTimeMillis());
        mqttDeviceCurrentDto.setMethod("thing.event.property.post");

        JSONObject paramJson = new JSONObject();
        //网关
        String gatewayNum = ByteUtils.byteArrayToHexString(byteArray,2,2,false);
        //节点
        String nodeNum = ByteUtils.byteArrayToHexString(byteArray,4,2,false);
        //传感器
        String monitorNum = ByteUtils.byteArrayToHexString(byteArray,6,2,false);
        short gangjinYingli = ByteUtils.byteArrayToShort(byteArray,8);
        short shenya = ByteUtils.byteArrayToShort(byteArray,10);
        short tuya = ByteUtils.byteArrayToShort(byteArray,12);
        short Xzhendong =ByteUtils.byteArrayToShort(byteArray,14);
        short Yzhendong =ByteUtils.byteArrayToShort(byteArray,16);
        short Zzhendong =ByteUtils.byteArrayToShort(byteArray,18);
        int dianchidianya = ByteUtils.byteToInt(byteArray[20]);

        mqttDeviceCurrentDto.setDeviceCode(DEVICE_CODE_PREFIX+ "_"+gatewayNum +nodeNum + monitorNum);
        paramJson.put("steel_stress",new BigDecimal(gangjinYingli).
                multiply(new BigDecimal("3.3")).
                divide(new BigDecimal("4096"),2, RoundingMode.HALF_UP).
                multiply(new BigDecimal("1")));//量程
        paramJson.put("osmotic_pressure", new BigDecimal(shenya)
                .multiply(new BigDecimal("3.3"))
                .divide(new BigDecimal("4096"),2, RoundingMode.HALF_UP).
                multiply(new BigDecimal("1")));//量程
        paramJson.put("earth_pressure",new BigDecimal(tuya)
                .multiply(new BigDecimal("3.3"))
                .divide(new BigDecimal("4096"),2, RoundingMode.HALF_UP).
                multiply(new BigDecimal("1")));//量程
        paramJson.put("x_vibration_severity",new BigDecimal(Xzhendong)
                .multiply(new BigDecimal("3.3"))
                .divide(new BigDecimal("4096"),2, RoundingMode.HALF_UP).
                multiply(new BigDecimal("1")));//量程
        paramJson.put("y_vibration_severity",new BigDecimal(Yzhendong)
                .multiply(new BigDecimal("3.3"))
                .divide(new BigDecimal("4096"),2, RoundingMode.HALF_UP).
                multiply(new BigDecimal("1")));//量程
        paramJson.put("z_vibration_severity",new BigDecimal(Zzhendong)
                .multiply(new BigDecimal("3.3"))
                .divide(new BigDecimal("4096"),2, RoundingMode.HALF_UP).
                multiply(new BigDecimal("1")));//量程
        paramJson.put("battery_voltage",new BigDecimal(dianchidianya).divide(new BigDecimal(10),2, RoundingMode.HALF_UP));

        mqttDeviceCurrentDto.setParams(paramJson);

        logger.info("解析结果：" + JSONObject.toJSONString(mqttDeviceCurrentDto));

        //发送解析结果到物联网平台mqtt
        mqttSendGateway.sendToMqtt(deviceTransferService.getIotPlatPropertyTopicV1(DEVICE_TYPE), JSONObject.toJSONString(mqttDeviceCurrentDto));

        logger.info("发送mqtt完成：TOPIC:" + deviceTransferService.getIotPlatPropertyTopicV1(DEVICE_TYPE) +"  PAYLOAD:"+ JSONObject.toJSONString(mqttDeviceCurrentDto));
        deviceLogInfluxService.addDeviceLog(mqttDeviceCurrentDto.getDeviceCode(),
                ByteUtils.byteArrayToHexString(byteArray),"deviceReport",System.currentTimeMillis(),0);
        return mqttDeviceCurrentDto.getDeviceCode().replace("dxgp_","");
    }

    /**
     * 向网关下发命令
     * @return
     */
    public String sendCommandToDevice(JSONObject serviceJson){
        try{
            JSONObject serviceData = serviceJson.getJSONObject("serviceData");
            JSONArray serviceParams = serviceJson.getJSONArray("serviceParam");
            String deviceCode = serviceJson.getString("deviceCode").replace("dxgp_","");
            String productId = serviceJson.getString("productId");
            ChannelHandlerContext ctx = BootNettyChannelInboundHandlerAdapter.getCtx(deviceCode.substring(0,4));

            if((serviceData.getString("identifier").equals("GET_CURRENT_DATA"))
                ||(serviceData.getString("identifier").equals("GET_ALARM_PARAM1"))
                ||(serviceData.getString("identifier").equals("GET_ALARM_PARAM2"))){
                StringBuilder commandSb = new StringBuilder();
                commandSb.append("FD FD ");
                commandSb.append(deviceCode); //网关+节点+传感器
                commandSb.append("03");   //读命令
                if(serviceData.getString("identifier").equals("GET_CURRENT_DATA")){
                    commandSb.append("00 00");//起始地址
                    commandSb.append("00 0A"); //寄存器个数
                }
                else if(serviceData.getString("identifier").equals("GET_ALARM_PARAM1")){

                    commandSb.append("10 00");//起始地址
                    commandSb.append("00 09"); //寄存器个数
                }
                else if(serviceData.getString("identifier").equals("GET_ALARM_PARAM2")){
                    commandSb.append("10 09");//起始地址
                    commandSb.append("00 04"); //寄存器个数
                }
                String crc16 = ByteUtils.getCRC16(commandSb.toString().replace(" ",""),false);
                commandSb.append(crc16);
                byte[] commandBytes = ByteUtils.hexStrToByteArray(commandSb.toString());
                if(ctx != null){
                    logger.info("预埋传感器命令下发："+ ByteUtils.byteArrayToHexString(commandBytes));
                    ctx.writeAndFlush(commandBytes);
                    deviceLogInfluxService.addDeviceLog(serviceJson.getString("deviceCode"),
                            ByteUtils.byteArrayToHexString(commandBytes),
                            serviceData.getString("identifier"),
                            System.currentTimeMillis(),0);
                }
                else{
                    logger.info("设备不在线，无法下发命令");
                }
            }
            else if(serviceData.getString("identifier").equals("SET_CONFIG_DATA1")){
                for(int i=0;i<serviceParams.size();i++){
                    JSONObject param = serviceParams.getJSONObject(i);
                    logger.info("参数" + i+":" + JSONObject.toJSONString(param));
                    if(StringUtils.isNotBlank(param.getString("value"))){
                        String identifier = param.getString("identifier");
                        
                        String valueStr = param.getString("value");
                        StringBuilder commandSb = new StringBuilder();
                        BigDecimal valueDecimal = BigDecimal.ZERO;
                        try{
                             valueDecimal = new BigDecimal(valueStr);
                        }
                        catch (Exception ex){
                            logger.error("error",ex);
                            continue;
                        }
                        if(valueDecimal.compareTo(BigDecimal.ZERO) == 0){
                            continue;
                        }
                        commandSb.append("FD FD");
                        commandSb.append(deviceCode); //网关+节点+传感器
                        commandSb.append("10");   //写命令
                        short valueShort = 0;
                        if(identifier.equals("sampling_period")){
                            //采样周期
                            commandSb.append("10 00");
                        }
                        else if(identifier.equals("upload_period")){
                            //上传周期
                            commandSb.append("10 01");
                        }
                        else if(identifier.equals("steel_stress_limit")){
                            //钢筋应力
                            valueShort=act4096ToAd(valueDecimal);
                            commandSb.append("10 02");
                        }
                        else if(identifier.equals("osmotic_pressure_limit")){
                            //渗压限
                            valueShort=act4096ToAd(valueDecimal);
                            commandSb.append("10 03");
                        }
                        else if(identifier.equals("earth_pressure_limit")){
                            //土压限
                            valueShort=act4096ToAd(valueDecimal);
                            commandSb.append("10 04");
                        }
                        else if(identifier.equals("x_limit")){
                            //X震动限
                            valueShort=act4096ToAd(valueDecimal);
                            commandSb.append("10 04");
                        }
                        else if(identifier.equals("y_limit")){
                            //Y震动限
                            valueShort=act4096ToAd(valueDecimal);
                            commandSb.append("10 05");
                        }
                        else if(identifier.equals("z_limit")){
                            //Z震动限
                            valueShort=act4096ToAd(valueDecimal);
                            commandSb.append("10 06");
                        }
                        else if(identifier.equals("bv_limit")){
                            //电压限
                            commandSb.append("10 07");
                        }
                        commandSb.append("00 01");//寄存器个数
                        commandSb.append("00 02");//字节数
                        commandSb.append(ByteUtils.byteArrayToHexString(ByteUtils.shortToByteArray(valueShort)));
//                        logger.info("计算crc16：" + commandSb.toString());
                        String crc16 = ByteUtils.getCRC16(commandSb.toString(),false);
                        commandSb.append(crc16);

                        byte[] commandBytes = ByteUtils.hexStrToByteArray(commandSb.toString());
                        logger.info("预埋传感器设置参数:" + ByteUtils.byteArrayToHexString(commandBytes));
                        if(ctx != null){
                            ctx.writeAndFlush(commandBytes);
                            deviceLogInfluxService.addDeviceLog(serviceJson.getString("deviceCode"),
                                    ByteUtils.byteArrayToHexString(commandBytes),
                                    serviceData.getString("identifier"),
                                    System.currentTimeMillis(),0);
                        }
                        else{
                            logger.info("设备不在线，无法下发命令");
                        }
                    }
                }
            }

        }
        catch (Exception ex){
            logger.error("error",ex);
        }
        return "";
    }
}
